//
//  LBWhiteBalanceFilter.mm
//  OpenGLGame
//
//  Created by Nguyen Cong Huy on 11/27/12.
//  Copyright (c) 2012 UIT. All rights reserved.
//

#include <iostream>
#include "LBWhiteBalanceFilter.h"
#include "LBGraphics.h"

char whiteBalanceFilterFragmentStr[] = ""
"precision highp float;  "
"uniform sampler2D texture;"
"varying highp vec2 vtexCoor;"
"varying vec4 vposition;"

"uniform lowp float temperature;"
"uniform lowp float tint;"

"const lowp vec3 warmFilter = vec3(0.93, 0.54, 0.0);"

"const mediump mat3 RGBtoYIQ = mat3(0.299, 0.587, 0.114, 0.596, -0.274, -0.322, 0.212, -0.523, 0.311);"
"const mediump mat3 YIQtoRGB = mat3(1.0, 0.956, 0.621, 1.0, -0.272, -0.647, 1.0, -1.105, 1.702);"

//contrast function (default 1.0)
"vec4 contrastColor(vec4 color, float contrast){"
"color.r = (color.r - 0.5)*contrast + 0.5;"
"color.g = (color.g - 0.5)*contrast + 0.5;"
"color.b = (color.b - 0.5)*contrast + 0.5;"
"color = clamp(color, 0.0, 1.0);"
"return color;"
"}"
//END contrast function

//brightness function (default 0.0)
"vec4 brightnessColor(vec4 color, float brightness){"
"color.r = color.r + brightness;"
"color.g = color.g + brightness;"
"color.b = color.b + brightness;"
"color = clamp(color, 0.0, 1.0);"
"return color;"
"}"
//END brightness function

// radial gradient color function
"vec4 radialGradientColor(vec4 centerColor, vec4 outerColor, vec2 myPosition, vec2 centerPosition){"
"    float distance = clamp(distance(myPosition, centerPosition), 0.0, 1.0);"
"    return mix(centerColor, outerColor, distance);"
"}"
// radial gradient color function

// hard light blend function
"vec4 hardLight(vec4 base, vec4 blend, float opacity){"
"   vec4 result =  base;"
"    if (blend.r > 0.5) result.r = 1.0 - (1.0-base.r) *(1.0-2.0*(blend.r-0.5));"
"    else result.r = base.r * (2.0*blend.r);"

"    if (blend.g > 0.5) result.g = 1.0 - (1.0-base.g) *(1.0-2.0*(blend.g-0.5));"
"    else result.g = base.g * (2.0*blend.g);"

"    if (blend.b > 0.5) result.b = 1.0 - (1.0-base.b) *(1.0-2.0*(blend.b-0.5));"
"    else result.b = base.b * (2.0*blend.b);"

"    result = mix(base, result, opacity);"
"    return result;"
"}"
// END hard light blend function

// overlay function
"vec4 overlay(vec4 base, vec4 blend, float opacity){"
"    vec4 result =  base;"

"   if (base.r > 0.5) result.r = 1.0 - (1.0-2.0 * (base.r - 0.5)) * (1.0-blend.r); "
"   else result.r = (2.0 * base.r) * blend.r; "

"   if (base.g > 0.5) result.g = 1.0 - (1.0-2.0 * (base.g - 0.5)) * (1.0-blend.g); "
"   else result.g = (2.0 * base.g) * blend.g; "

"   if (base.b > 0.5) result.b = 1.0 - (1.0-2.0 * (base.b - 0.5)) * (1.0-blend.b); "
"   else result.b = (2.0 * base.b) * blend.b; "

"   result = mix(base, result, opacity);"

"   return result;"

"}"
// END overlay function

// soft light function
"vec4 softLight(vec4 base, vec4 blend, float opacity){"
"    vec4 result =  base;"

"    if (blend.r > 0.5) result.r = 1.0 - (1.0-base.r) * (1.0 - (blend.r-0.5));" 
"    if (blend.r <= 0.5) result.r = base.r * (blend.r + 0.5);"

"    if (blend.g > 0.5) result.g = 1.0 - (1.0-base.g) * (1.0 - (blend.g-0.5));" 
"    if (blend.g <= 0.5) result.g = base.g * (blend.g + 0.5);"

"    if (blend.b > 0.5) result.b = 1.0 - (1.0-base.b) * (1.0 - (blend.b-0.5));" 
"    if (blend.b <= 0.5) result.b = base.b * (blend.b + 0.5);"
"    result = mix(base, result, opacity);"
"    return result;"
"}"
// END soft light function

"void main()"
"{"
"	lowp vec4 source = texture2D(texture, vtexCoor);"
	
"	mediump vec3 yiq = RGBtoYIQ * source.rgb; //adjusting tint\n"
"	yiq.b = clamp(yiq.b + tint*0.5226*0.1, -0.5226, 0.5226);"
"	lowp vec3 rgb = YIQtoRGB * yiq;"

"	lowp vec3 processed = vec3("
"                              (rgb.r < 0.5 ? (2.0 * rgb.r * warmFilter.r) : (1.0 - 2.0 * (1.0 - rgb.r) * (1.0 - warmFilter.r))), //adjusting temperature\n"
"                              (rgb.g < 0.5 ? (2.0 * rgb.g * warmFilter.g) : (1.0 - 2.0 * (1.0 - rgb.g) * (1.0 - warmFilter.g))), "
"                              (rgb.b < 0.5 ? (2.0 * rgb.b * warmFilter.b) : (1.0 - 2.0 * (1.0 - rgb.b) * (1.0 - warmFilter.b))));"
    

" lowp  vec4 result = vec4(mix(rgb, processed, temperature), source.a);"

"	gl_FragColor = result;"
"}";

LBWhiteBalanceFilter::LBWhiteBalanceFilter(){
    init(0, whiteBalanceFilterFragmentStr);
    
    temperatureUniform = program->uniformIndex("temperature");
    tintUniform = program->uniformIndex("tint");
    
    temperature(5000);
    tint(0);
}
void LBWhiteBalanceFilter::temperature(int kelvinDegree){
    LBGraphics::getInstance()->useProgram(program);
    glUniform1f(temperatureUniform, kelvinDegree < 5000 ? 0.0004 * (float)(kelvinDegree-5000.0) : 0.00006 * (float)(kelvinDegree-5000.0));
}

void LBWhiteBalanceFilter::tint(int tintValue){
    LBGraphics::getInstance()->useProgram(program);
    glUniform1f(tintUniform, ((float)tintValue)/100);
}